package net.kosev.su.tetris;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;

import net.kosev.su.tetris.game.Block;
import net.kosev.su.tetris.game.Board;
import net.kosev.su.tetris.game.Type;
import net.kosev.su.tetris.game.Board.BoardObserver;
import net.kosev.su.tetris.tetrominoes.Tetromino;

public class TetrisGame extends Game implements BoardObserver {
	
	public static final int TILE_SIZE = Integer.parseInt(Config.getInstance().get("tile_size"));
	
	protected final Font mainFont = new Font("Arial", Font.BOLD, 22);
	protected final Font smallFont = new Font("Arial", Font.PLAIN, 14);
	
	protected Board board = new Board();
	
	protected boolean isGamePaused = false;
	protected boolean isGameOver = false;

	@Override
	public void init() {
		setGameTitle(Config.getInstance().get("game_title"));
		setWidth(Integer.parseInt(Config.getInstance().get("screen_width")));
		setHeight(Integer.parseInt(Config.getInstance().get("screen_height")));
		
		super.init();
		
		board.setBoardOserver(this);
		board.newGame();
	}
	
	protected KeyHandler keyHandler = new KeyHandler();

	@Override
	public void keyPressed(KeyEvent e) {
		int key = e.getKeyCode();
		
		Command cmd = new KeyCommand(keyHandler, key);
		cmd.execute();
	}
	
	class KeyHandler {
		public void handleKey(int key) {
			switch (key) {
			case KeyEvent.VK_LEFT:
			case KeyEvent.VK_A:
				board.moveTetromino(-1, 0);
				break;
			case KeyEvent.VK_RIGHT:
			case KeyEvent.VK_D:
				board.moveTetromino(1, 0);
				break;
			case KeyEvent.VK_UP:
			case KeyEvent.VK_W:
				board.rotateTetromino();
				break;
			case KeyEvent.VK_DOWN:
			case KeyEvent.VK_S:
			case KeyEvent.VK_SPACE:
				board.moveTetromino(0, 1);
				break;
			case KeyEvent.VK_P:
				board.togglePause();
				isGamePaused ^= true;
				break;
			case KeyEvent.VK_N:
				board.newGame();
				isGameOver = false;
				break;
			}
		}
	}

	@Override
	protected void updateGraphics(Graphics2D g) {
		// turn on anti-aliasing
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		drawBoard(g);
		drawNextTetromino(g);
		drawScore(g);
		drawHelpers(g);
	}
	
	//public interface
	
	protected void drawBoard(Graphics2D g) {
		Type[][] grid = board.getBoardForRendering();
		
		for (int i = 0; i < Board.HEIGHT; i++) {
			for (int j = 0; j < Board.WIDTH; j++) {
				Color c = getColorByType(grid[i][j]);
				
				Tile decoratedTile = new BorderDecorator(new GlossDecorator(new SimpleTile()));
				decoratedTile.draw(g, j * TILE_SIZE, i * TILE_SIZE, TILE_SIZE, c);
			}
		}
	}
	
	protected void drawNextTetromino(Graphics2D g) {
		g.setFont(mainFont);
		g.setColor(Color.BLACK);
		g.drawString("Next:", 220, 80);
		g.fillRect(300, 60, 120, 60);
		
		Tetromino tetromino = board.getNextTetromino();
		if (tetromino == null) {
			return;
		}
		
		Color color = getColorByType(tetromino.getType());
		
		final int marginLeft = 320;
		final int marginTop = 70;
		
		for (int i = 0; i < Tetromino.SIZE; i++) {
			Block block = tetromino.get(i);
			Tile decoratedTile = new BorderDecorator(new GlossDecorator(new SimpleTile()));
			decoratedTile.draw(g, block.x * TILE_SIZE + marginLeft, 
					block.y * TILE_SIZE + marginTop, TILE_SIZE, color);
		}
	}
	
	protected void drawScore(Graphics2D g) {
		g.setFont(mainFont);
		g.setColor(Color.BLACK);
		int score = board.getCurrentScore();
		g.drawString("Score: " + String.valueOf(score), 220, 30);
	}
	
	protected void drawHelpers(Graphics2D g) {
		g.setFont(smallFont);
		g.setColor(Color.BLACK);
		g.drawString("Use <A> and <D> to move", 220, 170);
		g.drawString("Use <S> or <Space> to speed up", 220, 220);
		g.drawString("Use <W> to rotate", 220, 270);
		g.drawString("For new game press <N>", 220, 320);
		g.drawString("For pause press <P>", 220, 370);
		
		if (isGameOver || isGamePaused) {
			g.setFont(mainFont);
			g.setColor(Color.WHITE);
			g.drawString(isGameOver ? "Game Over" : "Game Pause", 40, 180);
		}
	}
	
	protected Color getColorByType(Type type) {
		Color color = Colors.NONE;
		
		switch (type) {
		case BLUE: color = Colors.BLUE; break;
		case CYAN: color = Colors.CYAN; break;
		case GREEN: color = Colors.GREEN; break;
		case ORANGE: color = Colors.ORANGE; break;
		case PURPLE: color = Colors.PURPLE; break;
		case RED: color = Colors.RED; break;
		case YELLOW: color = Colors.YELLOW; break;
		}
		
		return color;
	}
	
	protected int currentMove = 0;

	@Override
	protected void updatePhysics(int deltaTime) {
		
		final int factor = Integer.parseInt(Config.getInstance().get("score_factor"));
		int moveLimit = 1000 - (board.getCurrentScore() / (5 * factor)) * 50;
		if (moveLimit < 100) {
			moveLimit = 100;
		}
		
		currentMove += deltaTime;
		if (currentMove >= moveLimit) {
			currentMove = 0;
			
			board.boardLoop();
		}
	}

	public void onEndGame(Board b) {
		isGameOver = true;
	}

}
